package com.netcracker.studportal.server.facade;

import java.io.File;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import com.netcracker.studportal.server.model.Exam;
import com.netcracker.studportal.server.model.ExamWithResult;
import com.netcracker.studportal.server.model.Material;
import com.netcracker.studportal.server.model.Professor;
import com.netcracker.studportal.server.model.Student;
import com.netcracker.studportal.server.util.FacadeUtil;
import com.netcracker.studportal.server.util.FactoryDAO;
import com.netcracker.studportal.server.util.FileUtil;
import com.netcracker.studportal.server.util.HibernateUtil;

public class FacadeProfessor {
	public static final Logger LOG = Logger.getLogger(FacadeProfessor.class);

	/**
	 * Set mark to student (update ExamWithResult field for corresponding student)
	 * 
	 * @param param
	 * 	JSONObject in format:
	 * 	"exam_id" 		: "value",
	 * 	"student_id" 	: "value",
	 * 	"mark" 			: "value",
	 * 	"note" 			: "value";
	 * 
	 * @return
	 * If successfully - null.
	 * 
	 * In case of errors:
	 * 	JSONObject in format:
	 *  "error" 		: "error_message",
	 *  "stacktrace" 	: "error_stacktrace";
	 */
	public String setExamResultByStudent(String param) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Method 'setExamResultByStudent' called with parameters = " + param);
		}
		if (StringUtils.isNotEmpty(param)) {
			try {
				ExamWithResult exRes = FacadeUtil.examWithResultParam(param);
				if (exRes == null)
					throw new IllegalArgumentException("Parameter not meet the requirements");
				if (exRes.getExam_id() == null)
					throw new IllegalArgumentException("Parameter 'exam_id' can't be empty!");
				if (exRes.getStudent_id() == null)
					throw new IllegalArgumentException("Parameter 'student_id' can't be empty!");

				ExamWithResult exRes2 = null;
				try {
					exRes2 = FactoryDAO.getExamWithResultDAO().getById(exRes.getExam_id(), exRes.getStudent_id());
				} catch (Exception e) {
					LOG.error("Error: ", e);
					e.printStackTrace();
				}

				if (exRes2 != null) {
					FactoryDAO.getExamWithResultDAO().Update(exRes);
				} else {
					throw new RuntimeException("Exam with exam_id = " + exRes.getExam_id() + " is not found!");
				}

			} catch (Exception e) {
				LOG.error("Error: ", e);
				JSONObject obj = new JSONObject();
				obj.put("error", e.getMessage());
				obj.put("stacktrace", ExceptionUtils.getFullStackTrace(e));

				return obj.toString();
			}
		}
		
		return null;
	}
	
	/**
	 * Get list of exams for corresponding professor
	 * 
	 * @param param
	 * 	JSONObject in format:
	 * 	"prof_id" : "value";
	 * 
	 * 
	 * @return 
	 * 	JSONArray of JSONObject in format:
	 *  "subject_name" 	: "value",
	 *  "subject_id" 	: "value",
	 *  "exam_id" 		: "value",
	 *  "prof_id" : "value",
	 *  "prof_first_name" : "value",
	 *  "patronymic" : "value",
	 *  "prof_last_name" : "value",
	 *  "type" : "value";
	 *  "exam_date" : "value";
	 *  
	 * In case of errors:
	 * 	JSONObject in format:
	 *  "error" 		: "error_message",
	 *  "stacktrace" 	: "error_stacktrace";
	 */
	public String getSheduleExamsByProfessor(String param) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Method 'getSheduleExamsByProfessor' called with parameters = " + param);
		}
		try {
			Map<String, String> inputParams = FacadeUtil.extractInputParams(param, new String[]{"prof_id"});
				
			Long profID = Long.parseLong(inputParams.get("prof_id"));
				
			Professor prof = FactoryDAO.getProfessorDAO().getById(profID);
				
			if (prof == null) {
				throw new RuntimeException("Professor with professor_id = " + profID + " is not found!");
			}

			List<Exam> ex_list = (List<Exam>) FactoryDAO.getExamDAO().getExamByProf(prof);
			if (ex_list != null && ex_list.size() > 0) {
				JSONArray list = new JSONArray();
				for (Exam e : ex_list) {
					list.add(e.kJSON());
				}

				String result = list.toString();
				return result;
			} else {
				// return empty JSON array, because professor doesn't have any exams
				return new JSONArray().toString();
			}
		} catch (Exception e) {
			LOG.error("Error: ", e);
			JSONObject obj = new JSONObject();
			obj.put("error", e.getMessage());
			obj.put("stacktrace", ExceptionUtils.getFullStackTrace(e));

			return obj.toString();
		}
	}
	
	/**
	 * Get list of students with marks for corresponding exam
	 * 
	 * @param param
	 * JSONObject in format:
	 * "exam_id" : "value"
	 * 
	 * @return
	 * JSONArray of JSONObject in format:
	 * "student_name" : "value"
	 * "student_id" : "value"
	 * "course" : "value"
	 * "group_num" : "value"
	 * "mark" : "value"
	 * "note" : "value"
	 * 
	 *  In case of errors:
	 * 	JSONObject in format:
	 *  "error" 		: "error_message",
	 *  "stacktrace" 	: "error_stacktrace";
	 *  
	 */
	public String getStudentResultsByExamID(String param){
		if (LOG.isDebugEnabled()) {
			LOG.debug("Method 'getExamResultsByID' called with parameters = " + param);
		}
		try{
			Map<String, String> inputParams = FacadeUtil.extractInputParams(param, new String[]{"exam_id"});
			Long exam_id = Long.parseLong(inputParams.get("exam_id"));
			
			List<Map<String,String>> m_list = FactoryDAO.getExamWithResultDAO().getStudentResultsByExamID(exam_id);
			
			JSONArray j_list = new JSONArray();
			if (m_list != null && m_list.size() > 0){
				for(Map<String,String> map : m_list){
					JSONObject jsonObj=new JSONObject();
					jsonObj.put("student_id", map.get("student_id"));
					jsonObj.put("mark", map.get("mark"));
					jsonObj.put("note", map.get("note"));
					jsonObj.put("student_name", map.get("student_name"));
					jsonObj.put("course", map.get("course"));
					jsonObj.put("group_num", map.get("group_num"));
					
					j_list.add(jsonObj);
				}
				String result = j_list.toString();
				return result;
			}else{
				return new JSONArray().toString();
			}	
		}catch (Exception e) {
			LOG.error("Error: ", e);
			JSONObject obj = new JSONObject();
			obj.put("error", e.getMessage());
			obj.put("stacktrace", ExceptionUtils.getFullStackTrace(e));

			return obj.toString();
		}
	}
	
	/**
	 * Get list of materials by corresponding exam
	 * 
	 * @param param
	 * JSONObject in format:
	 * "exam_id" : "value"
	 * 
	 * @return
	 * JSONArray of JSONObject in format:
	 * "material_name" : "value"
	 * "exam_id" : "exam_id"
	 * "material_id" : "material_id"
	 * 
	 *  In case of errors:
	 * 	JSONObject in format:
	 *  "error" 		: "error_message",
	 *  "stacktrace" 	: "error_stacktrace";
	 */
	public String getMaterialsByExam(String param){
		if (LOG.isDebugEnabled()) {
			LOG.debug("Method 'getMaterialsByExam' called with parameters = " + param);
		}
		try{
			Map<String, String> inputParams = FacadeUtil.extractInputParams(param, new String[]{"exam_id"});
			Long exam_id = Long.parseLong(inputParams.get("exam_id"));
			Exam ex = FactoryDAO.getExamDAO().getById(exam_id);
			
			if (ex == null) {
				throw new RuntimeException("Exam with exam_id = " + exam_id + " is not found!");
			}
			
			List<Material>  mater_list= (List<Material>)FactoryDAO.getMaterialDAO().getMaterialsByExam(ex);
			JSONArray list = new JSONArray();
			if(mater_list !=null && mater_list.size()>0){
				for(Material mater : mater_list){
					list.add(mater.kJSON());
				}
				String result = list.toString();
				return result;
			}else{
				return new JSONArray().toString();
			}	
			
		}catch (Exception e) {
			LOG.error("Error: ", e);
			JSONObject obj = new JSONObject();
			obj.put("error", e.getMessage());
			obj.put("stacktrace", ExceptionUtils.getFullStackTrace(e));

			return obj.toString();
		}
	}
	
	/**
	 * Allow to add new material for corresponding exam. 
	 * 
	 * @param param
	 * 	JSONObject in format: 
	 *  "exam_id"		: "value",
	 *  "material_name"	: "value",
	 *  "file_name"		: "value",
	 *  "file_content"	: "value";
	 * 
	 * @return
	 * JSONObject in format:
	 * 	"status" : "success"
	 * 
	 * In case of errors:
	 * 	JSONObject in format:
	 *  "error" 		: "error_message",
	 *  "stacktrace" 	: "error_stacktrace";
	 */
	public String addMaterialByExam(String param){
		if (LOG.isDebugEnabled()) {
			LOG.debug("Method 'addMaterialByExam' called with parameters = " + param);
		}
		try{
			String[] expectedKeys = new String[]{"exam_id", "material_name", "file_name", "file_content"};
			Map<String, String> inputParams = FacadeUtil.extractInputParams(param, expectedKeys);
			
			//String inp_path = inputParams.get("path");
			String fileContent = inputParams.get("file_content");
			String fileName = inputParams.get("file_name");
			
			//String materialFile = FileUtil.loadAndEncodeFile(inp_path);
			String pathToFile = FileUtil.decodeAndSaveFile(fileContent, fileName);	
			
			Material material = new Material();
			Exam exam = new Exam();
			exam.setId(Long.parseLong(inputParams.get("exam_id")));
			material.setExam(exam);
			material.setName(inputParams.get("material_name"));
			material.setPath(pathToFile);

			FactoryDAO.getMaterialDAO().Add(material);
			
			JSONObject result = new JSONObject();
			result.put("status", "success");
			return result.toJSONString();	
		}catch (Exception e) {
			LOG.error("Error: ", e);
			JSONObject obj = new JSONObject();
			obj.put("error", e.getMessage());
			obj.put("stacktrace", ExceptionUtils.getFullStackTrace(e));

			return obj.toString();
		}
	}
	/**
	 * Allow to delete corresponding material
	 * 
	 * @param param
	 * JSONObject in format:
	 * "material_id" : "value"
	 * 
	 * @return
	 * JSONObject in format:
	 * "status" : "success"
	 *  
	 *  In case of errors:
	 * 	JSONObject in format:
	 *  "error" 		: "error_message",
	 *  "stacktrace" 	: "error_stacktrace";
	 * 
	 */
	public String deleteMaterialByID(String param){
		if (LOG.isDebugEnabled()) {
			LOG.debug("Method 'deleteMaterialByID' called with parameters = " + param);
		}
		try{
			Map<String, String> inputParams = FacadeUtil.extractInputParams(param, new String[]{"material_id"});
			Long material_id = Long.parseLong(inputParams.get("material_id"));
			
			Material mater = FactoryDAO.getMaterialDAO().getById(material_id);
			if(mater == null){
				throw new RuntimeException("Material with material_id = " + material_id + " is not found!");
			}
			
			FileUtil.deleteFile(mater.getPath());
			
			FactoryDAO.getMaterialDAO().Delete(mater);
			JSONObject result = new JSONObject();
			result.put("status", "success");
			return result.toJSONString();
			
		}catch (Exception e) {
			LOG.error("Error: ", e);
			JSONObject obj = new JSONObject();
			obj.put("error", e.getMessage());
			obj.put("stacktrace", ExceptionUtils.getFullStackTrace(e));

			return obj.toString();
		}
	}
	/**
	 * Allow to delete all materials for corresponding exam.
	 * 
	 * @param param
	 * JSONObject in format:
	 * "exam_id" : "value"
	 * 
	 * @return
	 * JSONObject in format:
	 * "status" : "success"
	 *  
	 *  In case of errors:
	 * 	JSONObject in format:
	 *  "error" 		: "error_message",
	 *  "stacktrace" 	: "error_stacktrace";
	 */
	public String deleteMaterialsByExam(String param){
		if (LOG.isDebugEnabled()) {
			LOG.debug("Method 'deleteMaterialsByExam' called with parameters = " + param);
		}
		try{
			
			Map<String, String> inputParams = FacadeUtil.extractInputParams(param, new String[]{"exam_id"});
			Long exam_id = Long.parseLong(inputParams.get("exam_id"));
			Exam ex = FactoryDAO.getExamDAO().getById(exam_id);
			
			if (ex == null) {
				throw new RuntimeException("Exam with exam_id = " + exam_id + " is not found!");
			}
			
			List<Material>  mater_list= (List<Material>)FactoryDAO.getMaterialDAO().getMaterialsByExam(ex);
		
			for(Material m:mater_list){
				FileUtil.deleteFile(m.getPath());
				FactoryDAO.getMaterialDAO().Delete(m);
			}
			
			JSONObject result = new JSONObject();
			result.put("status", "success");
			return result.toJSONString();
		}catch (Exception e) {
			LOG.error("Error: ", e);
			JSONObject obj = new JSONObject();
			obj.put("error", e.getMessage());
			obj.put("stacktrace", ExceptionUtils.getFullStackTrace(e));

			return obj.toString();
		}
	}
	
	
	/**
	 * Method for getting list of Students for exam.
	 * 
	 * @param param
	 *  JSONObject in format:
	 *  "exam_id" : "value"
	 * 
	 * @return 
	 * 	JSONArray of JSONObject in format:
	 *  "student_id" 	: "value",
	 *  "stud_first_name" 		: "value",
	 *  "stud_last_name" : "value",
	 *  "course" : "value";
	 *  "group_num" : "value";
	 *  "stud_note" : "value";
	 *  "mark" : "value";
	 *  "ex_res_note" : "value";
	 * 
	 * In case of errors:
	 * 	JSONObject in format:
	 *  "error" 		: "error_message",
	 *  "stacktrace" 	: "error_stacktrace";
	 */
	public String getStudentsByExamID(String param){		
		if (LOG.isDebugEnabled()) {
			LOG.debug("Method 'getStudentsByExamID' called with parameters = " + param);
		}
		
		try {
			Map<String, String> inputParams = FacadeUtil.extractInputParams(param, new String[]{"exam_id"});
			
			Long exam_id = Long.parseLong(inputParams.get("exam_id"));
			
			List <Student> st_list = (List<Student>) FactoryDAO.getStudentDAO().getGetStudentsByExam(exam_id);	

			if(st_list != null && st_list.size() > 0) {
				JSONArray list = new JSONArray();
				for(Student s:st_list){
					JSONObject obj=new JSONObject();				
					if(s.getId()!=null)obj.put("student_id", s.getId().toString());
					obj.put("stud_first_name", s.getFirst_name());
					obj.put("stud_last_name", s.getLast_name());				
					if(s.getCourse()!=null) obj.put("course", s.getCourse());
					if(s.getGroup_num()!=null)obj.put("group_num", s.getGroup_num().toString());				
					obj.put("stud_note", s.getNote());
									
					List <ExamWithResult> ex_res=s.getExamWithResult();
					if(ex_res!=null && ex_res.size()>0)
					for(ExamWithResult ex:ex_res){
						if(ex.getExam_id()==exam_id) {
							if(ex.getMark()!=null) obj.put("mark",ex.getMark().toString());
							obj.put("ex_res_note", ex.getNote());
							break;
						}
					}
					list.add(obj);					
				}
				
				String result = list.toString();
				
				return result;
			} else {
				// return empty JSON array, because student doesn't have any exams
				return new JSONArray().toString();
			}
		} catch (Exception e) {
			LOG.error("Error: ", e);
			JSONObject obj = new JSONObject();
			obj.put("error", e.getMessage());
			obj.put("stacktrace", ExceptionUtils.getFullStackTrace(e));
				
			return obj.toString();
		}
		
	}
	
	
	/**
	 * Method for getting list of materials for exam.
	 * 
	 * @param param
	 *  JSONObject in format:
	 *  "material_id" : "value"
	 * 
	 * @return 
	 * 	JSONArray of JSONObject in format:
	 *  "material_file" 	: "value"
	 * 
	 * In case of errors:
	 * 	JSONObject in format:
	 *  "error" 		: "error_message",
	 *  "stacktrace" 	: "error_stacktrace";
	 */
	public String loadMaterialByID(String param) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Method 'loadMaterialByID' called with parameters = " + param);
		}

		try {
			Map<String, String> inputParams = FacadeUtil.extractInputParams(param, new String[]{"material_id"});
				
			Long materialID = Long.parseLong(inputParams.get("material_id"));
		
			Material material=FactoryDAO.getMaterialDAO().getById(materialID);
			
			if(material == null) {
				throw new Exception("Material with material_id = " + materialID + " is not found!");
			}
			
			String pathToFile = material.getPath();
			if(StringUtils.isNotEmpty(pathToFile)) {
				JSONObject mjson = new JSONObject();
				
				String fileName = new File(pathToFile).getName();
				mjson.put("file_name", fileName);
					
				String encodedFile = FileUtil.loadAndEncodeFile(pathToFile);
				mjson.put("file_content", encodedFile);
						
				return mjson.toJSONString();
			} else {
				throw new RuntimeException("Path to file with material = " + materialID + " is empty!");
			}
		} catch (Exception e) {
			LOG.error("Error: ", e);
			JSONObject obj = new JSONObject();
			obj.put("error", e.getMessage());
			obj.put("stacktrace", ExceptionUtils.getFullStackTrace(e));
			
			return obj.toString();
		}
	}
		
}
